/******************************************************************************/
/*  Class SETT_MEM                                                            */
/*  PO: S. Maslyakov, rusoil.9@gmail.com                                      */
/*                                                                            */
/*  Revision:     1.0                                                         */
/*  Date:         2011/01/08 21:54:33                                         */
/******************************************************************************/


#include "data_types.h"
#include "Core\core.h"
#include "Device\device.h"
#include "Auto\automem.h"
#include "TNKernel\tn.h"
#include "Sett_mem\sett_mem.h"



//==============================================================================
// App: Writa data at swop buffer
//==============================================================================
uint32_t SETT_MEM::WriteDataSwop(const __FMEM_DATA * const _pData) {

    // Addr rang test
    if (TestAddrRange(_pData->addr) == FALSE_T) {
        return eMEM_ADDR_ERROR;
    };

    // Capacity test
    if ((_pData->dataLen > GetSpaceToEnd(_pData->addr)) || (_pData->dataLen == 0)) {
        return eMEM_DATA_ERROR;
    };

    uint32_t err;
    uint32_t timeout;
    uint32_t countAddr;
    uint32_t countData;
    uint8_t * pBuff;
    __AT25DF_DATA hwData;
    __FMEM_DATA fmData;
    AUTOMEM Mem300(DEVICE::Get_mem_pool_300());

    // Get memory block
    pBuff = (uint8_t *)Mem300.AllocMemBlock(TN_MSEC_TO_TICK(500));
    if (pBuff == 0) {
        return eMEM_BUSY;
    };

    // Writing
    countAddr = _pData->addr;
    countData = 0;
    while (countData < _pData->dataLen) {
        uint32_t count;
        uint32_t stAddr;

        // Rewrite main sector in swop
        fmData.pBuff = pBuff;
        fmData.dataLen = AT25DF_PAGE_SIZE;
        stAddr = GetSectorStartAddr(countAddr);
        count = 0;

        while (count < GetSectorSize()) {
            // Read data from main
            fmData.addr = stAddr;
            timeout = 0;  // 5 sec
            while (1) {
                err = ReadData(&fmData);
                bool_t flgOk;

                switch (err)
                {
                    //----------------------------------------------------------
                    case eMEM_OK:
                      flgOk = TRUE_T;
                    break;

                    //----------------------------------------------------------
                    case eMEM_BUSY:
                      flgOk = FALSE_T;
                    break;

                    //----------------------------------------------------------
                    case eMEM_NOT_AVAILABLE:
                    //----------------------------------------------------------
                    case eMEM_ADDR_ERROR:
                    //----------------------------------------------------------
                    case eMEM_DATA_ERROR:
                    //----------------------------------------------------------
                    case eMEM_WRITE_EN_ERROR:
                    //----------------------------------------------------------
                    case eMEM_INTERNAL_ERROR:
                      return err;
                };

                if (flgOk == TRUE_T) {
                    break;
                };

                tn_task_sleep(TN_MSEC_TO_TICK(20));

                if (timeout++ > 250) {
                    return eMEM_BUSY;
                };
            };
            stAddr += AT25DF_PAGE_SIZE;

            // Write data to swop
            fmData.addr = count;
            err = m_pSwop->WriteData(&fmData);

            if (err != eMEM_OK) {
                return err;
            };
            count += AT25DF_PAGE_SIZE;
        };

        // Rewrite data from swop + new data
        stAddr = GetSectorStartAddr(countAddr);
        count = 0;

        while (count < GetSectorSize()) {
            // Read data from swop
            fmData.addr = count;
            timeout = 0;  // 5 sec
            while (1) {
                err = m_pSwop->ReadData(&fmData);
                bool_t flgOk;

                switch (err)
                {
                    //----------------------------------------------------------
                    case eMEM_OK:
                      flgOk = TRUE_T;
                    break;

                    //----------------------------------------------------------
                    case eMEM_BUSY:
                      flgOk = FALSE_T;
                    break;

                    //----------------------------------------------------------
                    case eMEM_NOT_AVAILABLE:
                    //----------------------------------------------------------
                    case eMEM_ADDR_ERROR:
                    //----------------------------------------------------------
                    case eMEM_DATA_ERROR:
                    //----------------------------------------------------------
                    case eMEM_WRITE_EN_ERROR:
                    //----------------------------------------------------------
                    case eMEM_INTERNAL_ERROR:
                      return err;
                };

                if (flgOk == TRUE_T) {
                    break;
                };

                tn_task_sleep(TN_MSEC_TO_TICK(20));

                if (timeout++ > 250) {
                    return eMEM_BUSY;
                };
            };
            count += AT25DF_PAGE_SIZE;

            // Change data
            if ((countAddr < (stAddr + AT25DF_PAGE_SIZE)) && (countData < _pData->dataLen)) {
                const uint32_t shift = countAddr - stAddr;
                const uint32_t len = (_pData->dataLen > (AT25DF_PAGE_SIZE - shift))
                    ? (AT25DF_PAGE_SIZE - shift) : _pData->dataLen;

                memcpy(pBuff + shift, _pData->pBuff + countData, len);
                countData += len;
                countAddr += len;
            };

            // Write data to main
            fmData.addr = stAddr;
            err = WriteData(&fmData);

            if (err != eMEM_OK) {
                return err;
            };
            stAddr += AT25DF_PAGE_SIZE;
        };
    };

    return eMEM_OK;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Writa swop buffer in main
//==============================================================================
uint32_t SETT_MEM::WriteSwopToMain(const __FMEM_DATA * const _pData) {

    // Addr rang test
    if ((TestAddrRange(_pData->addr) == FALSE_T)
          || (GetSectorStartAddr(_pData->addr) != _pData->addr)) {
        return eMEM_ADDR_ERROR;
    };

    uint32_t err;
    uint32_t timeout;
    uint32_t count;
    uint32_t stAddr;
    uint8_t * pBuff;
    __AT25DF_DATA hwData;
    __FMEM_DATA fmData;
    AUTOMEM Mem300(DEVICE::Get_mem_pool_300());

    // Get memory block
    pBuff = (uint8_t *)Mem300.AllocMemBlock(TN_MSEC_TO_TICK(500));
    if (pBuff == 0) {
        return eMEM_BUSY;
    };

    // Rewrite data from swop
    stAddr = GetSectorStartAddr(_pData->addr);
    count = 0;

    while (count < GetSectorSize()) {
        // Read data from swop
        fmData.addr = count;
        timeout = 0;  // 5 sec
        while (1) {
            err = m_pSwop->ReadData(&fmData);
            bool_t flgOk;

            switch (err)
            {
                //--------------------------------------------------------------
                case eMEM_OK:
                  flgOk = TRUE_T;
                break;

                //--------------------------------------------------------------
                case eMEM_BUSY:
                  flgOk = FALSE_T;
                break;

                //--------------------------------------------------------------
                case eMEM_NOT_AVAILABLE:
                //--------------------------------------------------------------
                case eMEM_ADDR_ERROR:
                //--------------------------------------------------------------
                case eMEM_DATA_ERROR:
                //--------------------------------------------------------------
                case eMEM_WRITE_EN_ERROR:
                //--------------------------------------------------------------
                case eMEM_INTERNAL_ERROR:
                  return err;
            };

            if (flgOk == TRUE_T) {
                break;
            };

            tn_task_sleep(TN_MSEC_TO_TICK(20));

            if (timeout++ > 250) {
                return eMEM_BUSY;
            };
        };
        count += AT25DF_PAGE_SIZE;

        // Write data to main
        fmData.addr = stAddr;
        err = WriteData(&fmData);

        if (err != eMEM_OK) {
            return err;
        };
        stAddr += AT25DF_PAGE_SIZE;
    };

    return eMEM_OK;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get start addr sector
//==============================================================================
uint32_t SETT_MEM::GetSectorStartAddr(const uint32_t _addr) {

    uint32_t addr = _addr;
    const uint32_t sect = GetSectorSize();

    while (addr >= sect) {
        addr -= sect;
    };

    return (_addr - addr);
}
//==============================================================================
//==============================================================================